#    Copyright (C) 2019 Mason Hock <mason@masonhock.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#


import gi

gi.require_version("Gst", "1.0")
from gi.repository import Gst

Gst.init(None)

from .misc import seconds_to_timestamp


class Player:
    def __init__(self):
        self.playbin = Gst.ElementFactory.make("playbin", "player")
        bus = self.playbin.get_bus()
        bus.enable_sync_message_emission()
        bus.add_signal_watch()

        self.queue = []
        self.index = None

        self.channel = None

        self.is_playing = False
        self.position_changed = False
        self.position = 0
        self.duration = 0

        self.playbin.connect("about-to-finish", self.on_about_to_finish)

    def is_ready(self):
        return len(self.queue) > 0 and self.index is not None

    def set_volume(self, value):
        self.playbin.set_property("volume", value)

    def set_playlist(self, playlist):
        if len(playlist) > 0:
            self.playlist = playlist
            self.set_index(0)
            self.play()

    def set_index(self, index):
        if len(self.queue) > 0:
            if index < 0:
                index = 0
            if index == len(self.queue):
                self.request_track()
            if index > len(self.queue) - 1:
                index = len(self.queue) - 1
            if self.index != index:
                self.index = index
                self.playbin.set_property("uri", self.queue[self.index]["uri"])

    def start_track(self, index):
        if len(self.queue) > 0:
            self.set_position(0)
            self.update_position()
            self.playbin.set_state(Gst.State.NULL)
            self.set_index(index)
            self.play()

    def queue_track(self, track):
        uri = (
            "http://mp3l.jamendo.com/?trackid="
            + track["track_id"].split(":")[1]
            + "&format=mp31"
        )
        self.queue.append({"track": track, "uri": uri})

    def play(self):
        if self.is_ready():
            self.is_playing = True
            self.playbin.set_state(Gst.State.PLAYING)

    def pause(self):
        if self.is_ready():
            self.is_playing = False
            self.playbin.set_state(Gst.State.PAUSED)

    def next(self):
        if self.is_ready():
            self.start_track(self.index + 1)

    def previous(self):
        if self.is_ready():
            query = self.playbin.query_position(Gst.Format.TIME)
            if query[0] and query[1] > 5000000000:
                self.set_position(0)
                self.update_position()
            else:
                self.start_track(self.index - 1)

    def get_now_playing(self):
        if self.is_ready():
            return self.queue[self.index]["track"]

    def update_gui(
        self,
        liststore,
        playback_bar,
        playback_bar_is_pressed,
        playback_timestamp,
        playpause_button,
    ):
        if self.is_ready():

            # update playback marker
            now_playing = self.get_now_playing()

            def update_icon(model, path, itr, track):
                if model.get_value(itr, 0) == track["track_id"]:
                    if self.is_playing:
                        model.set_value(itr, 1, "gtk-media-play")
                    else:
                        model.set_value(itr, 1, "gtk-media-pause")
                else:
                    model.set_value(itr, 1, None)

            liststore.foreach(update_icon, now_playing)

            if not playback_bar_is_pressed:

                # update playback bar position
                success, duration = self.playbin.query_duration(Gst.Format.TIME)
                if success:
                    self.duration = duration
                success, position = self.playbin.query_position(Gst.Format.TIME)
                if success:
                    self.position = position
                if self.duration > 0:
                    playback_bar.set_value(100 * self.position / self.duration)
                else:
                    playback_bar.set_value(0)

                # update timestamp
                position, duration = seconds_to_timestamp(
                    [self.position // 1000000000, self.duration // 1000000000]
                )
                playback_timestamp.set_text(position + "/" + duration)

            # update play/pause button
            if self.is_playing:
                playpause_button.set_stock_id("gtk-media-pause")
            else:
                playpause_button.set_stock_id("gtk-media-play")

    def set_position(self, position, percent=False):
        if self.is_ready():
            if percent:
                success, duration = self.playbin.query_duration(Gst.Format.TIME)
                if success:
                    self.position = position * duration / 100
                else:
                    return
            else:
                self.position = position
            self.position_changed = True

    def update_position(self):
        if self.is_ready():
            if self.position_changed:
                success, duration = self.playbin.query_duration(Gst.Format.TIME)
                if success:
                    self.playbin.seek_simple(
                        Gst.Format.TIME,
                        Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
                        self.position,
                    )
                self.position_changed = False

    def request_track(self):
        if self.channel is not None:
            self.queue_track(self.channel.get_random_track())

    def on_about_to_finish(self, data):
        self.set_index(self.index + 1)
